import isFunction from "../object/isFunction";
import isArray from "../object/isArray";
import map from './map'
import { deepGet } from "../object/property";

/**
 * 有些函数采用可变数量的参数，或者一些预期的参数
 * 在开头添加参数，然后使用可变数量的值进行操作上。 
 * 该帮助程序会累积该函数的所有剩余参数
 * 将参数长度（或显式的“ startIndex”）放入数组中
 * 最后一个参数 与ES6的“休息参数”相似。
 * @param func 
 * @param startIndex 
 */
export function restArguments(func: Function, startIndex?: number) {
  startIndex = startIndex == null ? func.length - 1 : +startIndex;
  return function (...args) {
    const length = Math.max(args.length - startIndex, 0)
    const rest = Array(length)
    for (let i = 0; i < length; i++) {
      rest[i] = args[i + startIndex];
    }
    switch (startIndex) {
      case 0: return func.call(this, rest)
      case 1: return func.call(this, args[0], rest)
      case 2: return func.apply(this, [args[0], args[1], rest])
    }
    var args1 = Array(startIndex + 1)
    for (let index in args1) {
      args1[index] = args[index]
    }
    args1[startIndex] = rest
    return func.apply(this, args1)
  }
}
const invoke = function tmp(obj, path, args) {
  var contextPath: any[], func: Function;
  if (isFunction(path)) {
    func = path
  } else if (isArray(path)) {
    contextPath = path.slice(0, 1)
    path = path[path.length - 1]
  }
  return map(obj, function (context) {
    var method = func
    if (!method) {
      if (contextPath && contextPath.length) {
        context = deepGet(context, contextPath)
      }
      if (context == null) return void 0
      method = context[path]
    }
    return method == null ? method : method.apply(context, args)
  })
}

export default restArguments(invoke)
